﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;

namespace Flagwind.Data
{
	public static class DataUtility
	{
		#region 私有字段

		private readonly static Dictionary<string, IDataProvider> _providers = new Dictionary<string, IDataProvider>();

		#endregion

		#region 私有常量

		private const string DEFAULT_PROVIDER = "Flagwind.Data.Providers.{0}, Flagwind.Data";

		#endregion

		#region 公共方法

		internal static int Insert(IEntity entity, List<string> fields, IDataProvider provider)
		{
			if(fields == null || fields.Count == 0)
			{
				return 0;
			}
			var parameters = new IDataParameter[fields.Count];
			var mappingName = entity.GetMappingName();
			var identityName = entity.GetIdentity();
			var sql = "INSERT INTO " + entity.GetSchemeTableName();
			var fieldNames = "";
			var values = "";
			var index = 0;
			//获取实体属性信息缓存
			var entityFieldsCache = EntityFieldsCache.Item(entity.GetType());
			foreach(string field in fields)
			{
				if(identityName != field)
				{
					fieldNames += ",[" + field + "]";
					string paraName = provider.ParameterChar + "P" + index.ToString();
					values += "," + paraName;
					parameters[index] = provider.GetParameter(paraName, entity.GetPropertyValue(field));
					//从缓存中获取当前field所对应的类型
					Type fieldType = entityFieldsCache.GetPropertyType(field);
					if(fieldType == typeof(string) && parameters[index].Value != null)
					{
						//为字符串类型的参数指定长度
						SetParameterSize(parameters[index], entity, field);
					}
					else if(fieldType == typeof(byte[]))
					{
						//为字节类型指定转换类型，防止空值时被当作字符串类型
						parameters[index].DbType = DbType.Binary;
					}
					index++;
				}
			}
			sql = sql + "(" + fieldNames.TrimStart(',') + ") VALUES (" + values.TrimStart(',') + ")";
			int count = 0;
			if(!string.IsNullOrEmpty(identityName))
			{
				//有自增字段
				object id = entity.GetPropertyValue(identityName);
				count = provider.ExecuteInsertQuery(sql, CommandType.Text, parameters, ref id);
				entity.SetFieldValue(identityName, Convert.ToInt32(id));
			}
			else
			{
				count = provider.ExecuteNonQuery(sql, CommandType.Text, parameters);
			}
			if(count > 0)
			{
				entity.ResetChanges();
			}
			return count;
		}

		internal static int Update(IEntity entity, List<string> fields, IDataProvider provider)
		{
			if(fields == null || fields.Count == 0)
			{
				return 0;
			}
			if(entity.GetPrimaryKey().Count == 0)
			{
				throw new Exception("当前实体类未指定主键字段。");
			}
			int fieldCount = fields.Count + entity.GetPrimaryKey().Count;
			if(fieldCount == 0)
			{
				throw new Exception("实体类属性字段为空。");
			}
			var parameters = new IDataParameter[fieldCount];
			var sql = "UPDATE " + entity.GetSchemeTableName() + " SET ";
			var values = "";
			var condition = "";
			int index = 0;
			//获取实体属性信息缓存
			var entityFieldsCache = EntityFieldsCache.Item(entity.GetType());
			//为解决 Access 问题，必须确保参数的顺序，故对条件参数的处理分开2次循环
			List<string> primaryKeys = new List<string>();
			//先处理更新的字段，主键字段不会被更新
			foreach(string field in fields)
			{
				if(entity.GetPrimaryKey().Contains(field))
				{
					primaryKeys.Add(field);
					continue;
				}
				string parameterName = provider.ParameterChar + "P" + index;
				values += ",[" + field + "]=" + parameterName;
				parameters[index] = provider.GetParameter(parameterName, entity.GetPropertyValue(field));
				//从缓存中获取当前field所对应的类型
				Type fieldType = entityFieldsCache.GetPropertyType(field);
				if(fieldType == typeof(string) && parameters[index].Value != null)
				{
					//为字符串类型的参数指定长度
					SetParameterSize(parameters[index], entity, field);
				}
				else if(fieldType == typeof(byte[]))
				{
					//为字节类型指定转换类型，防止空值时被当作字符串类型
					parameters[index].DbType = DbType.Binary;
				}
				index++;
			}
			//再处理条件
			foreach(string field in primaryKeys)
			{
				string paraName = provider.ParameterChar + "P" + index.ToString();
				//当前字段为主键，不能被更新
				condition += " AND [" + field + "]=" + paraName;
				parameters[index] = provider.GetParameter(paraName, entity.GetPropertyValue(field));
				//从缓存中获取当前field所对应的类型
				Type fieldType = entityFieldsCache.GetPropertyType(field);
				if(fieldType == typeof(string) && parameters[index].Value != null)
				{
					//为字符串类型的参数指定长度
					SetParameterSize(parameters[index], entity, field);
				}
				else if(fieldType == typeof(byte[]))
				{
					//为字节类型指定转换类型，防止空值时被当作字符串类型
					parameters[index].DbType = DbType.Binary;
				}
				index++;
			}
			if(condition == "")
			{
				foreach(string key in entity.GetPrimaryKey())
				{
					string paraName = provider.ParameterChar + "P" + index;
					condition += " AND [" + key + "]=" + paraName;
					parameters[index] = provider.GetParameter(paraName, entity.GetPropertyValue(key));
					//从缓存中获取当前field所对应的类型
					Type fieldType = entityFieldsCache.GetPropertyType(key);
					if(fieldType == typeof(string) && parameters[index].Value != null)
					{
						//为字符串类型的参数指定长度
						SetParameterSize(parameters[index], entity, key);
					}
					else if(fieldType == typeof(byte[]))
					{
						//为字节类型指定转换类型，防止空值时被当作字符串类型
						parameters[index].DbType = DbType.Binary;
					}
					index++;
				}
			}
			if(values == "")
			{
				throw new Exception("未指定主键字段之外的要更新的字段，请检查实体类的属性值是否更改过。");
			}
			sql = sql + values.TrimStart(',') + " WHERE " + condition.Substring(" AND ".Length);
			int count = provider.ExecuteNonQuery(sql, CommandType.Text, parameters);
			if(count > 0)
			{
				entity.ResetChanges();
			}
			return count;
		}

		internal static int Delete(IEntity entity, IDataProvider provider)
		{
			if(entity.GetPrimaryKey().Count == 0)
			{
				throw new Exception("当前实体类未指定主键字段。");
			}
			int fieldCount = entity.GetPropertyNames().Length;
			if(fieldCount == 0)
			{
				throw new Exception("实体类属性字段为空。");
			}
			var parameters = new IDataParameter[fieldCount];
			var sql = "DELETE FROM " + entity.GetSchemeTableName() + " WHERE ";
			var values = "";
			var condition = "";
			var index = 0;
			foreach(string key in entity.GetPrimaryKey())
			{
				string paraName = provider.ParameterChar + "P" + index;
				condition += " AND [" + key + "]=" + paraName;
				parameters[index] = provider.GetParameter(paraName, entity.GetPropertyValue(key));
				index++;
			}
			sql = sql + values.TrimStart(',') + " " + condition.Substring(" AND ".Length);
			int count = provider.ExecuteNonQuery(sql, CommandType.Text, parameters);
			return count;
		}

		internal static bool Exists(IEntity entity, IDataProvider provider)
		{
			if(entity.GetPrimaryKey().Count == 0)
			{
				throw new Exception("当前实体类未指定主键字段。");
			}
			if(entity.GetPropertyNames() == null)
			{
				throw new Exception("当前实体类属性字段未初始化。");
			}
			int fieldCount = entity.GetPropertyNames().Length;
			if(fieldCount == 0)
			{
				throw new Exception("实体类属性字段数量为空。");
			}
			var parameters = new IDataParameter[fieldCount];
			var sql = "SELECT Count(*) ";
			var condition = "";
			var index = 0;
			foreach(string key in entity.GetPrimaryKey())
			{
				string paraName = provider.ParameterChar + "P" + index;
				condition += " AND [" + key + "]=" + paraName;
				parameters[index] = provider.GetParameter(paraName, entity.GetPropertyValue(key));
				index++;
			}
			sql = sql + " FROM " + entity.GetSchemeTableName() + " WHERE " + condition.Substring(" AND ".Length);
			var result = provider.ExecuteScalar(sql, CommandType.Text, parameters);
			int count = Convert.ToInt32(result);
			return count > 0;
		}

		internal static bool Fill(IEntity entity, IDataProvider provider)
		{
			if(entity.GetPrimaryKey().Count == 0)
			{
				throw new Exception("当前实体类未指定主键字段。");
			}
			if(entity.GetPropertyNames() == null)
			{
				throw new Exception("当前实体类属性字段未初始化。");
			}
			int fieldCount = entity.GetPropertyNames().Length;
			if(fieldCount == 0)
			{
				throw new Exception("实体类属性字段为空。");
			}
			var parameters = new IDataParameter[entity.GetPrimaryKey().Count];
			var sql = "SELECT ";
			var condition = "";
			var index = 0;
			foreach(string key in entity.GetPrimaryKey())
			{
				string paraName = provider.ParameterChar + "P" + index;
				condition += " AND [" + key + "]=" + paraName;
				parameters[index] = provider.GetParameter(paraName, entity.GetPropertyValue(key));
				index++;
			}
			sql = sql + string.Join(",", Utility.PrepareSqlFields(entity.GetPropertyNames())) + " FROM [" + entity.GetMappingName() + "] WHERE " + condition.Substring(" AND ".Length);
			IDataReader reader = provider.ExecuteDataReader(sql, CommandType.Text, parameters);
			bool flag = false;
			if(reader != null)
			{
				try
				{
					if(reader.Read())
					{
						int count = reader.FieldCount;
						object[] values = new object[count];
						reader.GetValues(values);
						entity.SetPropertyValues(values);
						flag = true;
					}
				}
				catch(Exception ex)
				{
					throw ex;
				}
				finally
				{
					reader.Close();
				}
			}
			return flag;
		}

		internal static List<T> ResolveEntityList<T>(IDataReader reader, string tableName = "") where T : class
		{
			List<T> result = new List<T>();
			using(reader)
			{
				if(reader.Read())
				{
					int fieldCount = reader.FieldCount;
					string[] names = new string[fieldCount];
					for(int i = 0; i < fieldCount; i++)
					{
						names[i] = reader.GetName(i);
					}
					T t = EntityBuilder.CreateEntity<T>();
					if(t is IEntity)
					{
						IEntity entity = t as IEntity;
						entity.SetPropertyNames(names);
						if(!string.IsNullOrEmpty(tableName))
						{
							entity.ChangeMappingTable(tableName);
						}
						do
						{
							object[] values = new object[fieldCount];
							reader.GetValues(values);
							IEntity entityNew = (IEntity)entity.Clone();
							entityNew.SetPropertyValues(values);
							result.Add(entityNew as T);
						} while(reader.Read());
					}
					else if(t is IDataReadable)
					{
						do
						{
							((IDataReadable)t).Read(reader, fieldCount, names);
							result.Add(t);
							t = EntityBuilder.CreateEntity<T>();
						} while(reader.Read());
					}
					else
					{
						var accessors = new INamedMemberAccessor[fieldCount];
						var accessor = new MemberAccessor();
						for(int i = 0; i < fieldCount; i++)
						{
							accessors[i] = accessor.FindAccessor<T>(reader.GetName(i));
						}
						do
						{
							for(int i = 0; i < fieldCount; i++)
							{
								if(!reader.IsDBNull(i))
								{
									accessors[i].SetValue(t, reader.GetValue(i));
								}
							}
							result.Add(t);
							t = EntityBuilder.CreateEntity<T>();
						} while(reader.Read());
					}
				}
			}
			return result;
		}

		internal static T ResolveEntity<T>(IDataReader reader) where T : class
		{
			using(reader)
			{
				if(reader.Read())
				{
					int fieldCount = reader.FieldCount;
					string[] names = new string[fieldCount];
					for(int i = 0; i < fieldCount; i++)
					{
						names[i] = reader.GetName(i);
					}
					object[] values = new object[fieldCount];
					reader.GetValues(values);
					T t = EntityBuilder.CreateEntity<T>();
					IEntity entity = t as IEntity;
					entity.SetPropertyNames(names);
					entity.SetPropertyValues(values);
					return t;
				}
			}
			return null;
		}

		internal static string FillParameter<T>(Command command, T entity, IDataProvider provider, out IDataParameter[] parameters) where T : IEntity
		{
			string sql = command.ToString();
			Dictionary<string, TableNameField> paramsDictionary = command.Parameters;
			int index = 0;
			string condition = string.Empty;
			//为 DateTime 类型增加
			int tempCount = entity.GetPropertyChangedList().Count(temp => entity.GetPropertyValue(temp) is DateTime);
			//不存在Where
			if(paramsDictionary == null || paramsDictionary.Count < 1)
			{
				parameters = new IDataParameter[entity.GetPropertyChangedList().Count + tempCount];
				foreach(string key in entity.GetPropertyChangedList())
				{
					IDataParameter parameter = provider.GetParameter();
					string parameterName = provider.ParameterChar + "P" + index.ToString();
					if(entity.GetPropertyValue(key) is string)
					{
						condition += " AND [" + key + "] like " + parameterName;
						parameter.ParameterName = parameterName;
						parameter.Value = "%" + entity.GetPropertyValue(key) + "%";
					}
					else
					{
						if(entity.GetPropertyValue(key) is DateTime)
						{
							condition += " AND [" + key + "] >= " + parameterName;
							parameter.ParameterName = parameterName;
							parameter.Value = entity.GetPropertyValue(key);
							//---时间比较当前时间-明天之间
							parameters[index] = parameter;
							index++;
							parameter = provider.GetParameter();
							parameterName = provider.ParameterChar + "P" + index.ToString();
							condition += " AND [" + key + "] < " + parameterName;
							parameter.ParameterName = parameterName;
							parameter.Value = ((DateTime)entity.GetPropertyValue(key)).AddDays(1).ToShortDateString();
							//---时间比较当前时间-明天之间
						}
						else
						{
							condition += " AND [" + key + "] = " + parameterName;
							parameter.ParameterName = parameterName;
							parameter.Value = entity.GetPropertyValue(key);
						}
					}
					parameters[index] = parameter;
					index++;
				}
				string tableName = entity.GetSchemeTableName();
				int whereIndex = sql.IndexOf(tableName);
				sql = sql.Substring(0, whereIndex + tableName.Length) + (string.IsNullOrEmpty(condition) ? " " : (" WHERE " + condition.Substring(" AND ".Length))) + sql.Substring(whereIndex + tableName.Length);
			}
			else
			{
				int fieldCount = paramsDictionary.Count;
				parameters = new IDataParameter[fieldCount + entity.GetPropertyChangedList().Count + tempCount];
				foreach(string name in paramsDictionary.Keys)
				{
					IDataParameter parameter = provider.GetParameter();
					parameter.ParameterName = name;
					parameter.Value = paramsDictionary[name].FieldValue;
					parameters[index] = parameter;
					index++;
				}
				foreach(string key in entity.GetPropertyChangedList())
				{
					IDataParameter parameter = provider.GetParameter();
					string parameterName = provider.ParameterChar + "P" + index;
					if(entity.GetPropertyValue(key) is string)
					{
						condition += " AND [" + key + "] like " + parameterName;
						parameter.ParameterName = parameterName;
						parameter.Value = "%" + entity.GetPropertyValue(key) + "%";
					}
					else
					{
						if(entity.GetPropertyValue(key) is DateTime)
						{
							condition += " AND [" + key + "] >= " + parameterName;
							parameter.ParameterName = parameterName;
							parameter.Value = entity.GetPropertyValue(key);
							//---时间比较当前时间-明天之间
							parameters[index] = parameter;
							index++;
							parameter = provider.GetParameter();
							parameterName = provider.ParameterChar + "P" + index.ToString();
							condition += " AND [" + key + "] < " + parameterName;
							parameter.ParameterName = parameterName;
							parameter.Value = ((DateTime)entity.GetPropertyValue(key)).AddDays(1).ToShortDateString();
							//---时间比较当前时间-明天之间
						}
						else
						{
							condition += " AND [" + key + "] = " + parameterName;
							parameter.ParameterName = parameterName;
							parameter.Value = entity.GetPropertyValue(key);
						}
					}
					parameters[index] = parameter;
					index++;
				}
				sql = sql.ToUpper();
				int whereIndex = sql.IndexOf(" WHERE", System.StringComparison.Ordinal);
				condition = string.IsNullOrEmpty(condition) ? "" : condition.Substring(" AND ".Length) + " AND";
				sql = sql.Substring(0, whereIndex + 6) + condition + sql.Substring(whereIndex + 6);
			}

			#region 分页

			if(command.PageEnable)
			{
				switch(provider.ProviderType)
				{
					case DataProviderType.Access:
					case DataProviderType.SqlServer:
					case DataProviderType.SqlServerCe:
						//如果含有Order By 子句，则不能使用主键分页
						if(command.haveJoinOpt || sql.IndexOf("order by", StringComparison.OrdinalIgnoreCase) > 0)
						{
							sql = SqlPager.MakeSQLStringByPage(DataProviderType.SqlServer, sql, "", command.PageSize, command.PageIndex, command.RecordCount);
						}
						else
						{
							if(command.PageOrderDesc)
							{
								sql = SqlPager.GetDescPageSQLbyPrimaryKey(command.PageIndex, command.PageSize, command.sql_fields, command.sql_table, command.PageField, command.sql_condition);
							}
							else
							{
								sql = SqlPager.GetAscPageSQLbyPrimaryKey(command.PageIndex, command.PageSize, command.sql_fields, command.sql_table, command.PageField, command.sql_condition);
							}
						}
						break;
					default:
						sql = SqlPager.MakeSQLStringByPage(provider.ProviderType, sql, "", command.PageSize, command.PageIndex, command.RecordCount);
						break;
				}
			}

			#endregion

			return sql;
		}

		internal static string GetMapSql(Type entityType)
		{
			return AnonymousAccess.GetMapSql(entityType);
		}

		internal static IDataParameter[] GetParameters(Dictionary<string, TableNameField> dictionary, IDataProvider provider)
		{
			if(dictionary == null)
			{
				return null;
			}
			var index = 0;
			var parameters = new IDataParameter[dictionary.Count];
			foreach(string key in dictionary.Keys)
			{
				object value = dictionary[key];
				if(value is IDataParameter)
				{
					parameters[index] = (IDataParameter)value;
				}
				else
				{
					string paraName = key.StartsWith("@") ? key.Substring(1) : key;

					var tnf = dictionary[key];
					parameters[index] = provider.GetParameter(paraName, tnf.FieldValue);
					if(tnf.Name != null && parameters[index].Value != null && parameters[index].Value.GetType() == typeof(string))
					{
						//增加字符串长度的检查,如果值得长度大于定义的长度,抛出异常提示
						int size = tnf.Entity.GetFieldSize(tnf.Field);
						//如果字段不是text等类型
						if(size != -1)
						{
							int length = parameters[index].Value.ToString().Length;
							if(length > size)
							{
								throw new NotSupportedException("当前实体类映射的字段" + paraName + " 长度没有定义或者长度小于了当前实际值的长度：" + length + "，请在实体类定义里面使用 SetProperty 的重载方法指定合适的字段长度。");
							}
							((IDbDataParameter)parameters[index]).Size = size;
						}
					}
				}
				index++;
			}
			return parameters;
		}

		internal static SqlInfo GetSqlInfo(Command oql, Type entityType, IDataProvider provider, bool single)
		{
			string sql = "";
			Dictionary<string, TableNameField> parameters = null;
			//处理用户查询映射的实体类
			if(oql.EntityMap == MappingType.SqlMap)
			{
				if(!Utility.EntitySqlMapCache.ContainsKey(oql.sql_table))
				{
					string tempView = GetMapSql(entityType);
					Utility.EntitySqlMapCache.Add(oql.sql_table, tempView);
				}
				sql = oql.GetMapSQL(Utility.EntitySqlMapCache[oql.sql_table]);
				//如果用户本身没有初始化参数对象，则这里声明一个
				parameters = new Dictionary<string, TableNameField>();
				if(oql.InitParameters != null)
				{
					foreach(string name in oql.InitParameters.Keys)
					{
						TableNameField field = new TableNameField();
						field.FieldValue = oql.InitParameters[name];
						parameters.Add(name, field);
					}
				}
				if(oql.Parameters != null && oql.Parameters.Count > 0)
				{
					foreach(string name in oql.Parameters.Keys)
					{
						parameters.Add(name, oql.Parameters[name]);
					}
				}
			}
			else if(oql.EntityMap == MappingType.StoredProcedure)
			{
				string script = "";
				//获取SQL-MAP脚本
				if(Utility.EntitySqlMapCache.ContainsKey(oql.sql_table))
				{
					script = Utility.EntitySqlMapCache[oql.sql_table];
				}
				else
				{
					script = GetMapSql(entityType);
					Utility.EntitySqlMapCache.Add(oql.sql_table, script);
				}
				//对SQL-MAP格式的参数进行解析
				DataCommand command = new DataCommand(script, CommandType.StoredProcedure, provider);
				sql = command.CommandText;
				IDataParameter[] paras = command.Parameters;
				if(oql.InitParameters != null && oql.InitParameters.Count > 0)
				{
					parameters = new Dictionary<string, TableNameField>();
					try
					{
						foreach(IDataParameter para in paras)
						{
							string key = para.ParameterName.TrimStart(provider.ParameterChar.ToCharArray());
							para.Value = oql.InitParameters[key];
							parameters.Add(key, new TableNameField()
							{
								FieldValue = para
							});
						}
					}
					catch(KeyNotFoundException exKey)
					{
						throw new KeyNotFoundException("'存储过程实体类'的初始化参数中没有找到指定的参数名，请检查参数定义和设置。", exKey);
					}
					catch(Exception ex)
					{
						throw ex;
					}
				}
				else
				{
					if(paras.Length > 0)
					{
						throw new Exception("当前'存储过程实体类'需要提供初始化参数，请设置OQL对象的InitParameters属性");
					}
				}
				SqlInfo info = new SqlInfo(sql, parameters);
				info.CommandType = CommandType.StoredProcedure;
				return info;
			}
			else
			{
				sql = oql.ToString();
				parameters = oql.Parameters;
			}
			if(oql.PageEnable && (!single || oql.RecordCount <= 0))
			{
				switch(provider.ProviderType)
				{
					case DataProviderType.Access:
					case DataProviderType.SqlServer:
					case DataProviderType.SqlServerCe:
						//如果含有Order By 子句，则不能使用主键分页
						if(oql.haveJoinOpt || sql.IndexOf("order by", StringComparison.OrdinalIgnoreCase) > 0)
						{
							sql = SqlPager.MakeSQLStringByPage(DataProviderType.SqlServer, sql, "", oql.PageSize, oql.PageIndex, oql.RecordCount);
						}
						else
						{
							//如果是字符串类型的主键，下面的分页可能不准确
							if(oql.PageOrderDesc)
							{
								sql = SqlPager.GetDescPageSQLbyPrimaryKey(oql.PageIndex, oql.PageSize, oql.sql_fields, oql.sql_table, oql.PageField, oql.sql_condition);
							}
							else
							{
								sql = SqlPager.GetAscPageSQLbyPrimaryKey(oql.PageIndex, oql.PageSize, oql.sql_fields, oql.sql_table, oql.PageField, oql.sql_condition);
							}
						}
						break;
					default:
						sql = SqlPager.MakeSQLStringByPage(provider.ProviderType, sql, "", oql.PageSize, oql.PageIndex, oql.RecordCount);
						break;
				}
			}
			SqlInfo result = new SqlInfo(sql, parameters);
			result.CommandType = CommandType.Text;
			result.TableName = oql.GetEntityTableName();
			return result;
		}

		internal static string FindFieldNameInSql(string sql, string paraName, string paraChar)
		{
			if(!paraName.StartsWith(paraChar))
			{
				paraName = paraChar + paraName;
			}
			string whereTempStr = sql.Substring(sql.IndexOf("Where", StringComparison.OrdinalIgnoreCase) + 5).Trim();
			string fildTempStr = whereTempStr.Substring(0, whereTempStr.IndexOf(paraName));
			int a = fildTempStr.LastIndexOf('[');
			int b = fildTempStr.LastIndexOf(']');
			string fieldStr = fildTempStr.Substring(a + 1, b - a - 1);
			return fieldStr;
		}

		#endregion

		#region 数据访问提供程序

		/// <summary>
		/// 获取一个数据访问提供程序。
		/// </summary>
		/// <param name="providerName">完整的提供程序名称。</param>
		/// <returns>数据访问提供程序实例。</returns>
		public static IDataProvider GetProvider(string providerName)
		{
			if(string.IsNullOrWhiteSpace(providerName))
			{
				throw new ArgumentNullException("providerName");
			}
			// 组装默认提供程序名称
			if(providerName.IndexOf(',') == -1)
			{
				providerName = string.Format(DEFAULT_PROVIDER, providerName);
			}
			string[] providerInfo = providerName.Split(',');
			if(providerInfo.Length != 2)
			{
				throw new ArgumentException("providerName");
			}
			return GetProvider(providerInfo[0].Trim(), providerInfo[1].Trim());
		}

		/// <summary>
		/// 获取一个数据访问提供程序。
		/// </summary>
		/// <param name="providerType">提供程序类型。</param>
		/// <param name="providerAssembly">提供程序所在程序集名称。</param>
		/// <returns>数据访问提供程序实例。</returns>
		public static IDataProvider GetProvider(string providerType, string providerAssembly)
		{
			if(string.IsNullOrWhiteSpace(providerType))
			{
				throw new ArgumentNullException("providerType");
			}
			if(string.IsNullOrWhiteSpace(providerAssembly))
			{
				throw new ArgumentNullException("providerAssembly");
			}
			// 缓存键
			var key = string.Format("{0}_{1}", providerAssembly, providerType);
			// 从缓存获取
			if(_providers.ContainsKey(key))
			{
				return _providers[key];
			}
			// 加载程序集
			var assembly = Assembly.Load(providerAssembly);
			// 获取类型
			var type = assembly.GetType(providerType);
			// 创建实例
			var instance = Activator.CreateInstance(type) as IDataProvider;
			if(instance == null)
			{
				throw new ArgumentException(string.Format("当前指定的提供程序：\"{0}\" 不是 \"Flagwind.Data.IDataProvider\" 的具体实现类。", providerType));
			}
			// 加入缓存
			_providers.Add(key, instance);
			return instance;
		}

		#endregion

		#region 私有方法

		private static void SetParameterSize(IDataParameter parameter, IEntity entity, string field)
		{
			if(parameter.Value != null && parameter.Value is string)
			{
				int size = entity.GetFieldSize(field);
				if(size > 0)
				{
					((IDbDataParameter)parameter).Size = size;
				}
			}
		}

		#endregion
	}
}